/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */// vim:cindent:ts=2:et:sw=2:/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. *//* representation of one line within a block frame, a CSS line box */#include"nsLineBox.h"#include"mozilla/ArenaObjectID.h"#include"mozilla/Assertions.h"#include"mozilla/Likely.h"#include"mozilla/WritingModes.h"#include"nsBidiPresUtils.h"#include"nsFrame.h"#include"nsIFrameInlines.h"#include"nsPresArena.h"#include"nsPrintfCString.h"#include"mozilla/Sprintf.h"#ifdef DEBUGstaticint32_tctorCount;int32_tnsLineBox::GetCtorCount(){returnctorCount;}#endif#ifndef _MSC_VER// static nsLineBox constant; initialized in the header file.constuint32_tnsLineBox::kMinChildCountForHashtable;#endifusingnamespacemozilla;nsLineBox::nsLineBox(nsIFrame*aFrame,int32_taCount,boolaIsBlock):mFirstChild(aFrame),mWritingMode(),mContainerSize(-1,-1),mBounds(WritingMode())// mBounds will be initialized with the correct// writing mode when it is set,mFrames(),mAscent(),mAllFlags(0),mData(nullptr){// Assert that the union elements chosen for initialisation are at// least as large as all other elements in their respective unions, so// as to ensure that no parts are missed.static_assert(sizeof(mFrames)>=sizeof(mChildCount),"nsLineBox init #1");static_assert(sizeof(mAllFlags)>=sizeof(mFlags),"nsLineBox init #2");static_assert(sizeof(mData)>=sizeof(mBlockData),"nsLineBox init #3");static_assert(sizeof(mData)>=sizeof(mInlineData),"nsLineBox init #4");MOZ_COUNT_CTOR(nsLineBox);#ifdef DEBUG++ctorCount;NS_ASSERTION(!aIsBlock||aCount==1,"Blocks must have exactly one child");nsIFrame*f=aFrame;for(int32_tn=aCount;n>0;f=f->GetNextSibling(),--n){NS_ASSERTION(aIsBlock==f->IsBlockOutside(),"wrong kind of child frame");}#endifstatic_assert(static_cast<int>(StyleClear::Max)<=15,"FlagBits needs more bits to store the full range of ""break type ('clear') values");mChildCount=aCount;MarkDirty();mFlags.mBlock=aIsBlock;}nsLineBox::~nsLineBox(){MOZ_COUNT_DTOR(nsLineBox);if(MOZ_UNLIKELY(mFlags.mHasHashedFrames)){deletemFrames;}Cleanup();}nsLineBox*NS_NewLineBox(nsIPresShell*aPresShell,nsIFrame*aFrame,boolaIsBlock){returnnew(aPresShell)nsLineBox(aFrame,1,aIsBlock);}nsLineBox*NS_NewLineBox(nsIPresShell*aPresShell,nsLineBox*aFromLine,nsIFrame*aFrame,int32_taCount){nsLineBox*newLine=new(aPresShell)nsLineBox(aFrame,aCount,false);newLine->NoteFramesMovedFrom(aFromLine);newLine->mContainerSize=aFromLine->mContainerSize;returnnewLine;}voidnsLineBox::StealHashTableFrom(nsLineBox*aFromLine,uint32_taFromLineNewCount){MOZ_ASSERT(!mFlags.mHasHashedFrames);MOZ_ASSERT(GetChildCount()>=int32_t(aFromLineNewCount));mFrames=aFromLine->mFrames;mFlags.mHasHashedFrames=1;aFromLine->mFlags.mHasHashedFrames=0;aFromLine->mChildCount=aFromLineNewCount;// remove aFromLine's frames that aren't on this linensIFrame*f=aFromLine->mFirstChild;for(uint32_ti=0;i<aFromLineNewCount;f=f->GetNextSibling(),++i){mFrames->RemoveEntry(f);}}voidnsLineBox::NoteFramesMovedFrom(nsLineBox*aFromLine){uint32_tfromCount=aFromLine->GetChildCount();uint32_ttoCount=GetChildCount();MOZ_ASSERT(toCount<=fromCount,"moved more frames than aFromLine has");uint32_tfromNewCount=fromCount-toCount;if(MOZ_LIKELY(!aFromLine->mFlags.mHasHashedFrames)){aFromLine->mChildCount=fromNewCount;MOZ_ASSERT(toCount<kMinChildCountForHashtable);}elseif(fromNewCount<kMinChildCountForHashtable){// aFromLine has a hash table but will not have it after moving the frames// so this line can steal the hash table if it needs it.if(toCount>=kMinChildCountForHashtable){StealHashTableFrom(aFromLine,fromNewCount);}else{deleteaFromLine->mFrames;aFromLine->mFlags.mHasHashedFrames=0;aFromLine->mChildCount=fromNewCount;}}else{// aFromLine still needs a hash table.if(toCount<kMinChildCountForHashtable){// remove the moved frames from itnsIFrame*f=mFirstChild;for(uint32_ti=0;i<toCount;f=f->GetNextSibling(),++i){aFromLine->mFrames->RemoveEntry(f);}}elseif(toCount<=fromNewCount){// This line needs a hash table, allocate a hash table for it since that// means fewer hash ops.nsIFrame*f=mFirstChild;for(uint32_ti=0;i<toCount;f=f->GetNextSibling(),++i){aFromLine->mFrames->RemoveEntry(f);// toCount RemoveEntry}SwitchToHashtable();// toCount PutEntry}else{// This line needs a hash table, but it's fewer hash ops to steal// aFromLine's hash table and allocate a new hash table for that line.StealHashTableFrom(aFromLine,fromNewCount);// fromNewCount RemoveEntryaFromLine->SwitchToHashtable();// fromNewCount PutEntry}}}void*nsLineBox::operatornew(size_tsz,nsIPresShell*aPresShell){returnaPresShell->AllocateByObjectID(eArenaObjectID_nsLineBox,sz);}voidnsLineBox::Destroy(nsIPresShell*aPresShell){this->nsLineBox::~nsLineBox();aPresShell->FreeByObjectID(eArenaObjectID_nsLineBox,this);}voidnsLineBox::Cleanup(){if(mData){if(IsBlock()){deletemBlockData;}else{deletemInlineData;}mData=nullptr;}}#ifdef DEBUG_FRAME_DUMPstaticvoidListFloats(FILE*out,constchar*aPrefix,constnsFloatCacheList&aFloats){nsFloatCache*fc=aFloats.Head();while(fc){nsCStringstr(aPrefix);nsIFrame*frame=fc->mFloat;str+=nsPrintfCString("floatframe@%p ",static_cast<void*>(frame));if(frame){nsAutoStringframeName;frame->GetFrameName(frameName);str+=NS_ConvertUTF16toUTF8(frameName).get();}else{str+="\n###!!! NULL out-of-flow frame";}fprintf_stderr(out,"%s\n",str.get());fc=fc->Next();}}constchar*nsLineBox::BreakTypeToString(StyleClearaBreakType)const{switch(aBreakType){caseStyleClear::None:return"nobr";caseStyleClear::Left:return"leftbr";caseStyleClear::Right:return"rightbr";caseStyleClear::InlineStart:return"inlinestartbr";caseStyleClear::InlineEnd:return"inlineendbr";caseStyleClear::Both:return"leftbr+rightbr";caseStyleClear::Line:return"linebr";caseStyleClear::Max:return"leftbr+rightbr+linebr";}return"unknown";}char*nsLineBox::StateToString(char*aBuf,int32_taBufSize)const{snprintf(aBuf,aBufSize,"%s,%s,%s,%s,%s,before:%s,after:%s[0x%x]",IsBlock()?"block":"inline",IsDirty()?"dirty":"clean",IsPreviousMarginDirty()?"prevmargindirty":"prevmarginclean",IsImpactedByFloat()?"impacted":"not impacted",IsLineWrapped()?"wrapped":"not wrapped",BreakTypeToString(GetBreakTypeBefore()),BreakTypeToString(GetBreakTypeAfter()),mAllFlags);returnaBuf;}voidnsLineBox::List(FILE*out,int32_taIndent,uint32_taFlags)const{nsCStringstr;while(aIndent-->0){str+=" ";}List(out,str.get(),aFlags);}voidnsLineBox::List(FILE*out,constchar*aPrefix,uint32_taFlags)const{nsCStringstr(aPrefix);charcbuf[100];str+=nsPrintfCString("line %p: count=%d state=%s ",static_cast<constvoid*>(this),GetChildCount(),StateToString(cbuf,sizeof(cbuf)));if(IsBlock()&&!GetCarriedOutBEndMargin().IsZero()){str+=nsPrintfCString("bm=%d ",GetCarriedOutBEndMargin().get());}nsRectbounds=GetPhysicalBounds();str+=nsPrintfCString("{%d,%d,%d,%d} ",bounds.x,bounds.y,bounds.width,bounds.height);if(mWritingMode.IsVertical()||!mWritingMode.IsBidiLTR()){str+=nsPrintfCString("{%s: %d,%d,%d,%d; cs=%d,%d} ",mWritingMode.DebugString(),IStart(),BStart(),ISize(),BSize(),mContainerSize.width,mContainerSize.height);}if(mData&&(!mData->mOverflowAreas.VisualOverflow().IsEqualEdges(bounds)||!mData->mOverflowAreas.ScrollableOverflow().IsEqualEdges(bounds))){str+=nsPrintfCString("vis-overflow=%d,%d,%d,%d scr-overflow=%d,%d,%d,%d ",mData->mOverflowAreas.VisualOverflow().x,mData->mOverflowAreas.VisualOverflow().y,mData->mOverflowAreas.VisualOverflow().width,mData->mOverflowAreas.VisualOverflow().height,mData->mOverflowAreas.ScrollableOverflow().x,mData->mOverflowAreas.ScrollableOverflow().y,mData->mOverflowAreas.ScrollableOverflow().width,mData->mOverflowAreas.ScrollableOverflow().height);}fprintf_stderr(out,"%s<\n",str.get());nsIFrame*frame=mFirstChild;int32_tn=GetChildCount();nsCStringpfx(aPrefix);pfx+=" ";while(--n>=0){frame->List(out,pfx.get(),aFlags);frame=frame->GetNextSibling();}if(HasFloats()){fprintf_stderr(out,"%s> floats <\n",aPrefix);ListFloats(out,pfx.get(),mInlineData->mFloats);}fprintf_stderr(out,"%s>\n",aPrefix);}nsIFrame*nsLineBox::LastChild()const{nsIFrame*frame=mFirstChild;int32_tn=GetChildCount()-1;while(--n>=0){frame=frame->GetNextSibling();}returnframe;}#endifint32_tnsLineBox::IndexOf(nsIFrame*aFrame)const{int32_ti,n=GetChildCount();nsIFrame*frame=mFirstChild;for(i=0;i<n;i++){if(frame==aFrame){returni;}frame=frame->GetNextSibling();}return-1;}boolnsLineBox::IsEmpty()const{if(IsBlock())returnmFirstChild->IsEmpty();int32_tn;nsIFrame*kid;for(n=GetChildCount(),kid=mFirstChild;n>0;--n,kid=kid->GetNextSibling()){if(!kid->IsEmpty())returnfalse;}if(HasBullet()){returnfalse;}returntrue;}boolnsLineBox::CachedIsEmpty(){if(mFlags.mDirty){returnIsEmpty();}if(mFlags.mEmptyCacheValid){returnmFlags.mEmptyCacheState;}boolresult;if(IsBlock()){result=mFirstChild->CachedIsEmpty();}else{int32_tn;nsIFrame*kid;result=true;for(n=GetChildCount(),kid=mFirstChild;n>0;--n,kid=kid->GetNextSibling()){if(!kid->CachedIsEmpty()){result=false;break;}}if(HasBullet()){result=false;}}mFlags.mEmptyCacheValid=true;mFlags.mEmptyCacheState=result;returnresult;}voidnsLineBox::DeleteLineList(nsPresContext*aPresContext,nsLineList&aLines,nsIFrame*aDestructRoot,nsFrameList*aFrames){nsIPresShell*shell=aPresContext->PresShell();// Keep our line list and frame list up to date as we// remove frames, in case something wants to traverse the// frame tree while we're destroying.while(!aLines.empty()){nsLineBox*line=aLines.front();if(MOZ_UNLIKELY(line->mFlags.mHasHashedFrames)){line->SwitchToCounter();// Avoid expensive has table removals.}while(line->GetChildCount()>0){nsIFrame*child=aFrames->RemoveFirstChild();MOZ_ASSERT(child==line->mFirstChild,"Lines out of sync");line->mFirstChild=aFrames->FirstChild();line->NoteFrameRemoved(child);child->DestroyFrom(aDestructRoot);}aLines.pop_front();line->Destroy(shell);}}boolnsLineBox::RFindLineContaining(nsIFrame*aFrame,constnsLineList::iterator&aBegin,nsLineList::iterator&aEnd,nsIFrame*aLastFrameBeforeEnd,int32_t*aFrameIndexInLine){NS_PRECONDITION(aFrame,"null ptr");nsIFrame*curFrame=aLastFrameBeforeEnd;while(aBegin!=aEnd){--aEnd;NS_ASSERTION(aEnd->LastChild()==curFrame,"Unexpected curFrame");if(MOZ_UNLIKELY(aEnd->mFlags.mHasHashedFrames)&&!aEnd->Contains(aFrame)){if(aEnd->mFirstChild){curFrame=aEnd->mFirstChild->GetPrevSibling();}continue;}// i is the index of curFrame in aEndint32_ti=aEnd->GetChildCount()-1;while(i>=0){if(curFrame==aFrame){*aFrameIndexInLine=i;returntrue;}--i;curFrame=curFrame->GetPrevSibling();}MOZ_ASSERT(!aEnd->mFlags.mHasHashedFrames,"Contains lied to us!");}*aFrameIndexInLine=-1;returnfalse;}nsCollapsingMarginnsLineBox::GetCarriedOutBEndMargin()const{NS_ASSERTION(IsBlock(),"GetCarriedOutBEndMargin called on non-block line.");return(IsBlock()&&mBlockData)?mBlockData->mCarriedOutBEndMargin:nsCollapsingMargin();}boolnsLineBox::SetCarriedOutBEndMargin(nsCollapsingMarginaValue){boolchanged=false;if(IsBlock()){if(!aValue.IsZero()){if(!mBlockData){mBlockData=newExtraBlockData(GetPhysicalBounds());}changed=aValue!=mBlockData->mCarriedOutBEndMargin;mBlockData->mCarriedOutBEndMargin=aValue;}elseif(mBlockData){changed=aValue!=mBlockData->mCarriedOutBEndMargin;mBlockData->mCarriedOutBEndMargin=aValue;MaybeFreeData();}}returnchanged;}voidnsLineBox::MaybeFreeData(){nsRectbounds=GetPhysicalBounds();if(mData&&mData->mOverflowAreas==nsOverflowAreas(bounds,bounds)){if(IsInline()){if(mInlineData->mFloats.IsEmpty()){deletemInlineData;mInlineData=nullptr;}}elseif(mBlockData->mCarriedOutBEndMargin.IsZero()){deletemBlockData;mBlockData=nullptr;}}}// XXX get rid of this???nsFloatCache*nsLineBox::GetFirstFloat(){MOZ_ASSERT(IsInline(),"block line can't have floats");returnmInlineData?mInlineData->mFloats.Head():nullptr;}// XXX this might be too eager to free memoryvoidnsLineBox::FreeFloats(nsFloatCacheFreeList&aFreeList){MOZ_ASSERT(IsInline(),"block line can't have floats");if(IsInline()&&mInlineData){if(mInlineData->mFloats.NotEmpty()){aFreeList.Append(mInlineData->mFloats);}MaybeFreeData();}}voidnsLineBox::AppendFloats(nsFloatCacheFreeList&aFreeList){MOZ_ASSERT(IsInline(),"block line can't have floats");if(IsInline()){if(aFreeList.NotEmpty()){if(!mInlineData){mInlineData=newExtraInlineData(GetPhysicalBounds());}mInlineData->mFloats.Append(aFreeList);}}}boolnsLineBox::RemoveFloat(nsIFrame*aFrame){MOZ_ASSERT(IsInline(),"block line can't have floats");if(IsInline()&&mInlineData){nsFloatCache*fc=mInlineData->mFloats.Find(aFrame);if(fc){// Note: the placeholder is part of the line's child list// and will be removed later.mInlineData->mFloats.Remove(fc);deletefc;MaybeFreeData();returntrue;}}returnfalse;}voidnsLineBox::SetFloatEdges(nscoordaStart,nscoordaEnd){MOZ_ASSERT(IsInline(),"block line can't have float edges");if(!mInlineData){mInlineData=newExtraInlineData(GetPhysicalBounds());}mInlineData->mFloatEdgeIStart=aStart;mInlineData->mFloatEdgeIEnd=aEnd;}voidnsLineBox::ClearFloatEdges(){MOZ_ASSERT(IsInline(),"block line can't have float edges");if(mInlineData){mInlineData->mFloatEdgeIStart=nscoord_MIN;mInlineData->mFloatEdgeIEnd=nscoord_MIN;}}voidnsLineBox::SetOverflowAreas(constnsOverflowAreas&aOverflowAreas){NS_FOR_FRAME_OVERFLOW_TYPES(otype){NS_ASSERTION(aOverflowAreas.Overflow(otype).width>=0,"illegal width for combined area");NS_ASSERTION(aOverflowAreas.Overflow(otype).height>=0,"illegal height for combined area");}nsRectbounds=GetPhysicalBounds();if(!aOverflowAreas.VisualOverflow().IsEqualInterior(bounds)||!aOverflowAreas.ScrollableOverflow().IsEqualEdges(bounds)){if(!mData){if(IsInline()){mInlineData=newExtraInlineData(bounds);}else{mBlockData=newExtraBlockData(bounds);}}mData->mOverflowAreas=aOverflowAreas;}elseif(mData){// Store away new value so that MaybeFreeData compares against// the right value.mData->mOverflowAreas=aOverflowAreas;MaybeFreeData();}}//----------------------------------------------------------------------staticnsLineBox*gDummyLines[1];nsLineIterator::nsLineIterator(){mLines=gDummyLines;mNumLines=0;mIndex=0;mRightToLeft=false;}nsLineIterator::~nsLineIterator(){if(mLines!=gDummyLines){delete[]mLines;}}/* virtual */voidnsLineIterator::DisposeLineIterator(){deletethis;}nsresultnsLineIterator::Init(nsLineList&aLines,boolaRightToLeft){mRightToLeft=aRightToLeft;// Count the linesint32_tnumLines=aLines.size();if(0==numLines){// Use gDummyLines so that we don't need null pointer checks in// the accessor methodsmLines=gDummyLines;returnNS_OK;}// Make a linear array of the linesmLines=newnsLineBox*[numLines];if(!mLines){// Use gDummyLines so that we don't need null pointer checks in// the accessor methodsmLines=gDummyLines;returnNS_ERROR_OUT_OF_MEMORY;}nsLineBox**lp=mLines;for(nsLineList::iteratorline=aLines.begin(),line_end=aLines.end();line!=line_end;++line){*lp++=line;}mNumLines=numLines;returnNS_OK;}int32_tnsLineIterator::GetNumLines(){returnmNumLines;}boolnsLineIterator::GetDirection(){returnmRightToLeft;}NS_IMETHODIMPnsLineIterator::GetLine(int32_taLineNumber,nsIFrame**aFirstFrameOnLine,int32_t*aNumFramesOnLine,nsRect&aLineBounds){NS_ENSURE_ARG_POINTER(aFirstFrameOnLine);NS_ENSURE_ARG_POINTER(aNumFramesOnLine);if((aLineNumber<0)||(aLineNumber>=mNumLines)){*aFirstFrameOnLine=nullptr;*aNumFramesOnLine=0;aLineBounds.SetRect(0,0,0,0);returnNS_OK;}nsLineBox*line=mLines[aLineNumber];*aFirstFrameOnLine=line->mFirstChild;*aNumFramesOnLine=line->GetChildCount();aLineBounds=line->GetPhysicalBounds();returnNS_OK;}int32_tnsLineIterator::FindLineContaining(nsIFrame*aFrame,int32_taStartLine){NS_PRECONDITION(aStartLine<=mNumLines,"Bogus line numbers");int32_tlineNumber=aStartLine;while(lineNumber!=mNumLines){nsLineBox*line=mLines[lineNumber];if(line->Contains(aFrame)){returnlineNumber;}++lineNumber;}return-1;}NS_IMETHODIMPnsLineIterator::CheckLineOrder(int32_taLine,bool*aIsReordered,nsIFrame**aFirstVisual,nsIFrame**aLastVisual){NS_ASSERTION(aLine>=0&&aLine<mNumLines,"aLine out of range!");nsLineBox*line=mLines[aLine];if(!line->mFirstChild){// empty line*aIsReordered=false;*aFirstVisual=nullptr;*aLastVisual=nullptr;returnNS_OK;}nsIFrame*leftmostFrame;nsIFrame*rightmostFrame;*aIsReordered=nsBidiPresUtils::CheckLineOrder(line->mFirstChild,line->GetChildCount(),&leftmostFrame,&rightmostFrame);// map leftmost/rightmost to first/last according to paragraph direction*aFirstVisual=mRightToLeft?rightmostFrame:leftmostFrame;*aLastVisual=mRightToLeft?leftmostFrame:rightmostFrame;returnNS_OK;}NS_IMETHODIMPnsLineIterator::FindFrameAt(int32_taLineNumber,nsPointaPos,nsIFrame**aFrameFound,bool*aPosIsBeforeFirstFrame,bool*aPosIsAfterLastFrame){NS_PRECONDITION(aFrameFound&&aPosIsBeforeFirstFrame&&aPosIsAfterLastFrame,"null OUT ptr");if(!aFrameFound||!aPosIsBeforeFirstFrame||!aPosIsAfterLastFrame){returnNS_ERROR_NULL_POINTER;}if((aLineNumber<0)||(aLineNumber>=mNumLines)){returnNS_ERROR_INVALID_ARG;}nsLineBox*line=mLines[aLineNumber];if(!line){*aFrameFound=nullptr;*aPosIsBeforeFirstFrame=true;*aPosIsAfterLastFrame=false;returnNS_OK;}if(line->ISize()==0&&line->BSize()==0)returnNS_ERROR_FAILURE;nsIFrame*frame=line->mFirstChild;nsIFrame*closestFromStart=nullptr;nsIFrame*closestFromEnd=nullptr;WritingModewm=line->mWritingMode;nsSizecontainerSize=line->mContainerSize;LogicalPointpos(wm,aPos,containerSize);int32_tn=line->GetChildCount();while(n--){LogicalRectrect=frame->GetLogicalRect(wm,containerSize);if(rect.ISize(wm)>0){// If pos.I() is inside this frame - this is itif(rect.IStart(wm)<=pos.I(wm)&&rect.IEnd(wm)>pos.I(wm)){closestFromStart=closestFromEnd=frame;break;}if(rect.IStart(wm)<pos.I(wm)){if(!closestFromStart||rect.IEnd(wm)>closestFromStart->GetLogicalRect(wm,containerSize).IEnd(wm))closestFromStart=frame;}else{if(!closestFromEnd||rect.IStart(wm)<closestFromEnd->GetLogicalRect(wm,containerSize).IStart(wm))closestFromEnd=frame;}}frame=frame->GetNextSibling();}if(!closestFromStart&&!closestFromEnd){// All frames were zero-width. Just take the first one.closestFromStart=closestFromEnd=line->mFirstChild;}*aPosIsBeforeFirstFrame=mRightToLeft?!closestFromEnd:!closestFromStart;*aPosIsAfterLastFrame=mRightToLeft?!closestFromStart:!closestFromEnd;if(closestFromStart==closestFromEnd){*aFrameFound=closestFromStart;}elseif(!closestFromStart){*aFrameFound=closestFromEnd;}elseif(!closestFromEnd){*aFrameFound=closestFromStart;}else{// we're between two framesnscoorddelta=closestFromEnd->GetLogicalRect(wm,containerSize).IStart(wm)-closestFromStart->GetLogicalRect(wm,containerSize).IEnd(wm);if(pos.I(wm)<closestFromStart->GetLogicalRect(wm,containerSize).IEnd(wm)+delta/2){*aFrameFound=closestFromStart;}else{*aFrameFound=closestFromEnd;}}returnNS_OK;}NS_IMETHODIMPnsLineIterator::GetNextSiblingOnLine(nsIFrame*&aFrame,int32_taLineNumber){aFrame=aFrame->GetNextSibling();returnNS_OK;}//----------------------------------------------------------------------#ifdef NS_BUILD_REFCNT_LOGGINGnsFloatCacheList::nsFloatCacheList():mHead(nullptr){MOZ_COUNT_CTOR(nsFloatCacheList);}#endifnsFloatCacheList::~nsFloatCacheList(){DeleteAll();MOZ_COUNT_DTOR(nsFloatCacheList);}voidnsFloatCacheList::DeleteAll(){nsFloatCache*c=mHead;while(c){nsFloatCache*next=c->Next();deletec;c=next;}mHead=nullptr;}nsFloatCache*nsFloatCacheList::Tail()const{nsFloatCache*fc=mHead;while(fc){if(!fc->mNext){break;}fc=fc->mNext;}returnfc;}voidnsFloatCacheList::Append(nsFloatCacheFreeList&aList){NS_PRECONDITION(aList.NotEmpty(),"Appending empty list will fail");nsFloatCache*tail=Tail();if(tail){NS_ASSERTION(!tail->mNext,"Bogus!");tail->mNext=aList.mHead;}else{NS_ASSERTION(!mHead,"Bogus!");mHead=aList.mHead;}aList.mHead=nullptr;aList.mTail=nullptr;}nsFloatCache*nsFloatCacheList::Find(nsIFrame*aOutOfFlowFrame){nsFloatCache*fc=mHead;while(fc){if(fc->mFloat==aOutOfFlowFrame){break;}fc=fc->Next();}returnfc;}nsFloatCache*nsFloatCacheList::RemoveAndReturnPrev(nsFloatCache*aElement){nsFloatCache*fc=mHead;nsFloatCache*prev=nullptr;while(fc){if(fc==aElement){if(prev){prev->mNext=fc->mNext;}else{mHead=fc->mNext;}returnprev;}prev=fc;fc=fc->mNext;}returnnullptr;}//----------------------------------------------------------------------#ifdef NS_BUILD_REFCNT_LOGGINGnsFloatCacheFreeList::nsFloatCacheFreeList():mTail(nullptr){MOZ_COUNT_CTOR(nsFloatCacheFreeList);}nsFloatCacheFreeList::~nsFloatCacheFreeList(){MOZ_COUNT_DTOR(nsFloatCacheFreeList);}#endifvoidnsFloatCacheFreeList::Append(nsFloatCacheList&aList){NS_PRECONDITION(aList.NotEmpty(),"Appending empty list will fail");if(mTail){NS_ASSERTION(!mTail->mNext,"Bogus");mTail->mNext=aList.mHead;}else{NS_ASSERTION(!mHead,"Bogus");mHead=aList.mHead;}mTail=aList.Tail();aList.mHead=nullptr;}voidnsFloatCacheFreeList::Remove(nsFloatCache*aElement){nsFloatCache*prev=nsFloatCacheList::RemoveAndReturnPrev(aElement);if(mTail==aElement){mTail=prev;}}voidnsFloatCacheFreeList::DeleteAll(){nsFloatCacheList::DeleteAll();mTail=nullptr;}nsFloatCache*nsFloatCacheFreeList::Alloc(nsIFrame*aFloat){NS_PRECONDITION(aFloat->GetStateBits()&NS_FRAME_OUT_OF_FLOW,"This is a float cache, why isn't the frame out-of-flow?");nsFloatCache*fc=mHead;if(mHead){if(mHead==mTail){mHead=mTail=nullptr;}else{mHead=fc->mNext;}fc->mNext=nullptr;}else{fc=newnsFloatCache();}fc->mFloat=aFloat;returnfc;}voidnsFloatCacheFreeList::Append(nsFloatCache*aFloat){NS_ASSERTION(!aFloat->mNext,"Bogus!");aFloat->mNext=nullptr;if(mTail){NS_ASSERTION(!mTail->mNext,"Bogus!");mTail->mNext=aFloat;mTail=aFloat;}else{NS_ASSERTION(!mHead,"Bogus!");mHead=mTail=aFloat;}}//----------------------------------------------------------------------nsFloatCache::nsFloatCache():mFloat(nullptr),mNext(nullptr){MOZ_COUNT_CTOR(nsFloatCache);}#ifdef NS_BUILD_REFCNT_LOGGINGnsFloatCache::~nsFloatCache(){MOZ_COUNT_DTOR(nsFloatCache);}#endif